﻿
// ProgramView.cpp: CProgramView 类的实现
//

#include "pch.h"
#include "framework.h"
// SHARED_HANDLERS 可以在实现预览、缩略图和搜索筛选器句柄的
// ATL 项目中进行定义，并允许与该项目共享文档代码。
#ifndef SHARED_HANDLERS
#include "Program.h"
#endif

#include "ProgramDoc.h"
#include "ProgramView.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#endif


// CProgramView

IMPLEMENT_DYNCREATE(CProgramView, CView)

BEGIN_MESSAGE_MAP(CProgramView, CView)
	ON_WM_RBUTTONDOWN()
	ON_WM_RBUTTONUP()
	ON_WM_LBUTTONDOWN()
	ON_WM_LBUTTONUP()
	//	ON_WM_NCMOUSEMOVE()
	ON_WM_MOUSEMOVE()
	ON_WM_MOUSEWHEEL()
	ON_COMMAND(ID_OBJ_EXPORT, &CProgramView::OnObjExport)
	ON_COMMAND(ID_MODE_FRAME, &CProgramView::OnModeFrame)
	ON_COMMAND(ID_MODE_VISIBLE_FRAME, &CProgramView::OnModeVisibleFrame)
	ON_WM_MBUTTONDOWN()
	ON_WM_MBUTTONUP()
	//	ON_WM_MBUTTONDBLCLK()
	ON_COMMAND(ID_MODE_DEFAULT, &CProgramView::OnModeDefault)
	ON_COMMAND(ID_MODE_TEXTURE_Phong, &CProgramView::OnModeTexturePhong)
	ON_COMMAND(ID_MODE_VERTEX, &CProgramView::OnModeVertex)
	ON_COMMAND(ID_BUFFER_SINGLE, &CProgramView::OnBufferSingle)
	ON_COMMAND(ID_BUFFER_DOUBLE, &CProgramView::OnBufferDouble)
	ON_COMMAND(ID_MODE_NORMAL, &CProgramView::OnModeNormal)
	//	ON_WM_TIMER()
	ON_WM_KEYDOWN()
	ON_WM_KEYUP()
	ON_WM_TIMER()
	ON_COMMAND(ID_SHADING_TRANSMISSION, &CProgramView::OnShadingTransmission)
END_MESSAGE_MAP()

// CProgramView 构造/析构

CProgramView::CProgramView() noexcept
{
	// TODO: 在此处添加构造代码
	zBuffer = new CZBuffer();
	obj.BindingCamera(&mainCamera);
	obj.BindingZBuffer(zBuffer);
	obj.BindingLight(&light);
	ui.BindingCamera(&mainCamera);
	ui.BindingModel(&obj);

	//t.SetMatrix(light.LightSource.L_Position);
}

CProgramView::~CProgramView()
{
}

BOOL CProgramView::PreCreateWindow(CREATESTRUCT& cs)
{
	// TODO: 在此处通过修改
	//  CREATESTRUCT cs 来修改窗口类或样式

	return CView::PreCreateWindow(cs);
}

// CProgramView 绘图

void CProgramView::OffsetClientRect(CDC* pDC)
{
	GetClientRect(&rect);
	pDC->SetMapMode(MM_ANISOTROPIC);//设置映射模式
	pDC->SetWindowExt(rect.Width(), rect.Height());//设置窗口
	pDC->SetViewportExt(rect.Width(), -rect.Height());//设置视区:x轴水平向右，y轴垂直向上
	pDC->SetViewportOrg(rect.Width() / 2, rect.Height() / 2);//客户区中心为坐标系原点
	rect.OffsetRect(-rect.Width() / 2, -rect.Height() / 2);//客户区矩形校正

	if (renderMode >= SHADING_PHONG || (renderMode == NormalMode && obj.texture.normal.isActive()))
		zBuffer->Initialize(rect.Width(), rect.Height());//初始化缓冲区
}

void CProgramView::OffsetScreenPoint(CPoint& point)
{
	point.x -= rect.Width() / 2;
	point.y -= rect.Height() / 2;
	point.y = -point.y;
}

void CProgramView::DoubleBuffer(CDC* pDC)
{
	CDC memDC;//声明内存DC
	CBitmap NewBitmap, * pOldBitmap;
	memDC.CreateCompatibleDC(pDC);//创建一个与显示DC兼容的内存DC 
	NewBitmap.CreateCompatibleBitmap(pDC, rect.Width(), rect.Height());//创建兼容内存位图 
	pOldBitmap = memDC.SelectObject(&NewBitmap);//将兼容位图选入内存DC
	//memDC.FillSolidRect(rect, pDC->GetBkColor());//按原来背景色填充客户区，否则是黑色
	memDC.FillSolidRect(rect, RGB(30, 32, 35));//按原来背景色填充客户区，否则是黑色
	memDC.SetMapMode(MM_ANISOTROPIC);//内存DC自定义坐标系
	memDC.SetWindowExt(rect.Width(), rect.Height());
	memDC.SetViewportExt(rect.Width(), -rect.Height());
	memDC.SetViewportOrg(rect.Width() / 2, rect.Height() / 2);
	if (renderMode >= SHADING_PHONG || (renderMode == NormalMode && obj.texture.normal.isActive()))
		ui.DrawMessageBox(GetDC(), rect, "渲染中");
	SingleBuffer(&memDC);
	pDC->BitBlt(rect.left, rect.top, rect.Width(), rect.Height(), &memDC, -rect.Width() / 2, -rect.Height() / 2, SRCCOPY); //将内存DC中的位图拷贝到设备DC
}

void CProgramView::SingleBuffer(CDC* pDC)
{
	pDC->FillRect(rect, new CBrush(RGB(30, 32, 35)));
	ui.DrawCoordinateAxis(pDC, cameraRotateAvtive);
	obj.DrawObject(pDC, renderMode);
	if (leftButtonDown)ui.DrawSelectRect(pDC, begin, end);
}

void CProgramView::OnDraw(CDC* pDC)
{
	//SetTimer(1, 1, NULL);
	CProgramDoc* pDoc = GetDocument();
	ASSERT_VALID(pDoc);
	if (!pDoc) return;

	OffsetClientRect(pDC);
	if (doubleBufferModeOn) DoubleBuffer(pDC);
	else SingleBuffer(pDC);
	if (renderMode >= SHADING_PHONG || (renderMode == NormalMode && obj.texture.normal.isActive()))
		zBuffer->Recycle();
}


// CProgramView 诊断

#ifdef _DEBUG
void CProgramView::AssertValid() const
{
	CView::AssertValid();
}

void CProgramView::Dump(CDumpContext& dc) const
{
	CView::Dump(dc);
}

CProgramDoc* CProgramView::GetDocument() const // 非调试版本是内联的
{
	ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CProgramDoc)));
	return (CProgramDoc*)m_pDocument;
}
#endif //_DEBUG


// CProgramView 消息处理程序


void CProgramView::OnRButtonDown(UINT nFlags, CPoint point)
{
	lastMode = renderMode;
	if (renderMode >= SHADING_PHONG || (renderMode == NormalMode && obj.texture.normal.isActive())) renderMode = FrameMode;
	// TODO: 在此添加消息处理程序代码和/或调用默认值
	cameraRotateAvtive = true;
	Invalidate(FALSE);
	CView::OnRButtonDown(nFlags, point);
}


void CProgramView::OnRButtonUp(UINT nFlags, CPoint point)
{
	renderMode = lastMode;
	// TODO: 在此添加消息处理程序代码和/或调用默认值
	cameraRotateAvtive = false;
	Invalidate(FALSE);
	CView::OnRButtonUp(nFlags, point);
}


void CProgramView::OnLButtonDown(UINT nFlags, CPoint point)
{
	lastMode = renderMode;
	if (renderMode >= SHADING_PHONG || (renderMode == NormalMode && obj.texture.normal.isActive())) renderMode = FrameMode;
	// TODO: 在此添加消息处理程序代码和/或调用默认值
	leftButtonDown = true;
	OffsetScreenPoint(point);
	//if(abs(point.x-ui.Xpos.x)<=ui.dirDiameter)
	begin.x = point.x;
	begin.y = point.y;
	end.x = point.x;
	end.y = point.y;
	if (!CtrlButtonPressed) ui.ClearSelectPoint();
	Invalidate(FALSE);
	CView::OnLButtonDown(nFlags, point);
}


void CProgramView::OnLButtonUp(UINT nFlags, CPoint point)
{
	renderMode = lastMode;
	// TODO: 在此添加消息处理程序代码和/或调用默认值
	leftButtonDown = false;
	Invalidate(FALSE);
	CView::OnLButtonUp(nFlags, point);
}


void CProgramView::OnMButtonDown(UINT nFlags, CPoint point)
{
	lastMode = renderMode;
	if (renderMode >= SHADING_PHONG || (renderMode == NormalMode && obj.texture.normal.isActive())) renderMode = FrameMode;
	// TODO: 在此添加消息处理程序代码和/或调用默认值
	cameraMoveAvtive = true;
	Invalidate(FALSE);
	CView::OnMButtonDown(nFlags, point);
}


void CProgramView::OnMButtonUp(UINT nFlags, CPoint point)
{
	renderMode = lastMode;
	// TODO: 在此添加消息处理程序代码和/或调用默认值
	cameraMoveAvtive = false;
	Invalidate(FALSE);
	CView::OnMButtonUp(nFlags, point);
}

void CProgramView::OnMouseMove(UINT nFlags, CPoint point)
{
	// TODO: 在此添加消息处理程序代码和/或调用默认值
	if (cameraRotateAvtive || cameraMoveAvtive)
	{
		SetCursor(AfxGetApp()->LoadStandardCursor(IDC_SIZEALL));
		if (cameraRotateAvtive)
		{
			double speed = 1800;
			double angle = 360;
			if (point.x - lastMousePoint.x < 0)mainCamera.Psi += abs(point.x - lastMousePoint.x) / speed * angle;
			if (point.x - lastMousePoint.x > 0)mainCamera.Psi -= abs(point.x - lastMousePoint.x) / speed * angle;
			if (point.y - lastMousePoint.y < 0)mainCamera.Phi += abs(point.y - lastMousePoint.y) / speed * angle;
			if (point.y - lastMousePoint.y > 0)mainCamera.Phi -= abs(point.y - lastMousePoint.y) / speed * angle;
			if (mainCamera.Phi > 180)mainCamera.Phi = 180;
			if (mainCamera.Phi < 0)mainCamera.Phi = 0;
		}
		else
		{
			if (point.x - lastMousePoint.x > 0)mainCamera.CameraOffset.x += abs(point.x - lastMousePoint.x) / 2.0;
			if (point.x - lastMousePoint.x < 0)mainCamera.CameraOffset.x -= abs(point.x - lastMousePoint.x) / 2.0;
			if (point.y - lastMousePoint.y < 0)mainCamera.CameraOffset.y += abs(point.y - lastMousePoint.y) / 2.0;
			if (point.y - lastMousePoint.y > 0)mainCamera.CameraOffset.y -= abs(point.y - lastMousePoint.y) / 2.0;
		}
		lastMousePoint = point;
		mainCamera.InitialParameter();
		Invalidate(FALSE);
	}
	else lastMousePoint = point;
	if (leftButtonDown)
	{
		OffsetScreenPoint(point);
		end.x = point.x;
		end.y = point.y;
		Invalidate(FALSE);
	}
	OffsetScreenPoint(point);
	CView::OnMouseMove(nFlags, point);
}


BOOL CProgramView::OnMouseWheel(UINT nFlags, short zDelta, CPoint pt)
{
	// TODO: 在此添加消息处理程序代码和/或调用默认值
	double speed = 1.1;
	int step = 10;
	if (zDelta < 0)
	{
		ui.scaleRate--;

		//调焦
		mainCamera.d /= speed;

		//调距
		//mainCamera.R /= speed;

		//希区柯克
		//mainCamera.d /= speed;
		//mainCamera.R /= speed;

		//相机位置
		//mainCamera.d -= step;
		//mainCamera.R -= step;
	}
	if (zDelta > 0)
	{
		ui.scaleRate++;

		//调焦
		mainCamera.d *= speed;

		//调距
		//mainCamera.R *= speed;

		//希区柯克
		//mainCamera.d *= speed;
		//mainCamera.R *= speed;

		//相机位置
		//mainCamera.d += step;
		//mainCamera.R += step;
	}
	mainCamera.InitialParameter();
	Invalidate(FALSE);
	return CView::OnMouseWheel(nFlags, zDelta, pt);
}


void CProgramView::OnObjExport()
{
	// TODO: 在此添加命令处理程序代码
	//设置文件筛选器
	CFileDialog OpenDlg(TRUE);
	OpenDlg.m_ofn.lpstrFilter =
		"Wavefont(*.obj;)\0*.obj;\0"\
		"Wavefont(*.stl;)\0*.stl;\0"\
		"\0";
	//创建对话框
	if (IDOK == OpenDlg.DoModal())
	{
		ui.DrawMessageBox(GetDC(), rect, "加载模型中");
		Invalidate(FALSE);
		obj.LoadFile((LPCTSTR)OpenDlg.GetPathName());
	}
}


void CProgramView::OnModeFrame()
{
	// TODO: 在此添加命令处理程序代码
	renderMode = FrameMode;
	Invalidate(FALSE);
}


void CProgramView::OnModeVisibleFrame()
{
	// TODO: 在此添加命令处理程序代码
	renderMode = Visible_FrameMode;
	Invalidate(FALSE);
}


void CProgramView::OnModeDefault()
{
	// TODO: 在此添加命令处理程序代码
	renderMode = DefaultMode;
	Invalidate(FALSE);
}


void CProgramView::OnModeTexturePhong()
{
	// TODO: 在此添加命令处理程序代码
	if (obj.ModleHaveNoNormal())
	{
		AfxMessageBox(_T("该模型没有法线数据!"));
		return;
	}
	renderMode = SHADING_PHONG;
	Invalidate(FALSE);
}


void CProgramView::OnModeVertex()
{
	// TODO: 在此添加命令处理程序代码
	renderMode = VertexMode;
	Invalidate(FALSE);
}


void CProgramView::OnBufferSingle()
{
	// TODO: 在此添加命令处理程序代码
	doubleBufferModeOn = false;
	Invalidate(FALSE);
}


void CProgramView::OnBufferDouble()
{
	// TODO: 在此添加命令处理程序代码
	doubleBufferModeOn = true;
	Invalidate(FALSE);
}


void CProgramView::OnModeNormal()
{
	// TODO: 在此添加命令处理程序代码
	if (obj.ModleHaveNoNormal())
	{
		AfxMessageBox(_T("该模型没有法线数据!"));
		return;
	}
	renderMode = NormalMode;
	Invalidate(FALSE);
}

void CProgramView::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags)
{
	// TODO: 在此添加消息处理程序代码和/或调用默认值

	switch (nChar)
	{
	case VK_CONTROL:CtrlButtonPressed = true; break;
	default:
		break;
	}

	Invalidate(FALSE);
	CView::OnKeyDown(nChar, nRepCnt, nFlags);
}


void CProgramView::OnKeyUp(UINT nChar, UINT nRepCnt, UINT nFlags)
{
	// TODO: 在此添加消息处理程序代码和/或调用默认值

	switch (nChar)
	{
	case VK_CONTROL:CtrlButtonPressed = false; break;
	default:
		break;
	}

	Invalidate(FALSE);
	CView::OnKeyUp(nChar, nRepCnt, nFlags);
}


void CProgramView::OnTimer(UINT_PTR nIDEvent)
{
	// TODO: 在此添加消息处理程序代码和/或调用默认值
	/*mainCamera.Psi++;
	mainCamera.InitialParameter();*/
	/*t.RotateY(-2);
	t.RotateX(1);*/
	Invalidate(FALSE);
	CView::OnTimer(nIDEvent);
}


void CProgramView::OnShadingTransmission()
{
	// TODO: 在此添加命令处理程序代码
	if (obj.ModleHaveNoNormal())
	{
		AfxMessageBox(_T("该模型没有法线数据!"));
		return;
	}
	renderMode = SHADING_TRANSMISSION;
	Invalidate(FALSE);
}
